package com.hdax.dm.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.hdax.dm.config.RabbitConfig;
import com.hdax.dm.constants.ResultEnumCode;
import com.hdax.dm.entity.item.DmItem;
import com.hdax.dm.entity.order.DmOrder;
import com.hdax.dm.entity.order.DmOrderLinkUser;
import com.hdax.dm.entity.order.OrderTxMsg;
import com.hdax.dm.entity.scheduler.DmSchedulerSeat;
import com.hdax.dm.entity.user.DmLinkUser;
import com.hdax.dm.exceptions.OrderException;
import com.hdax.dm.feign.order.ItemFeign;
import com.hdax.dm.feign.order.LinkUserFeign;
import com.hdax.dm.feign.order.SeatFeign;
import com.hdax.dm.feign.order.SeatPriceFeign;
import com.hdax.dm.service.OrderLinkUserService;
import com.hdax.dm.service.OrderService;
import com.hdax.dm.service.SubmitOrderService;
import com.hdax.dm.service.TxMsgService;
import com.hdax.dm.utils.DistributedLockHandler;
import com.hdax.dm.utils.TokenUtil;
import com.hdax.dm.vo.SubmitOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class SubmitOrderServiceImpl implements SubmitOrderService {

    @Autowired
    private ItemFeign itemFeign; //商品查询
    @Autowired
    private SeatFeign seatFeign;// 排期座位查询
    @Autowired
    private SeatPriceFeign seatPriceFeign;//座位价格
    @Autowired
    private LinkUserFeign linkUserFeign;//联系人
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderLinkUserService orderLinkUserService;

    @Autowired
    private DistributedLockHandler lockHandler;

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RabbitConfig rabbitConfig;
    @Autowired
    private TxMsgService txMsgService;
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public String addOrder(SubmitOrderVo vo, String token) throws OrderException {
        RLock lock = redissonClient.getLock("");
        boolean b = lock.tryLock();
        Map<String,Object> txMsg = new HashMap<>();

//        Lock lock = new Lock("lock", lockHandler.getUuid());
        if(b){
//        if(lockHandler.tryLock(lock)){
            try{
                //使用雪花算法生成唯一id
                Snowflake snowflake = new Snowflake();
                //订单编号
                String snowFlakeId = snowflake.nextIdStr();

                //根据请求参数查询商品信息(远程调用)
                DmItem dmItem = itemFeign.itemDetail(vo.getItemId());
                if(ObjectUtil.isNull(dmItem)){
                    log.error("add order has wrong: "+ ResultEnumCode.ITEM_NOT_EXISTS_ERR.getMessage());
                    throw new OrderException(ResultEnumCode.ITEM_NOT_EXISTS_ERR);
                }
                //查询用户信息
                Map<String, String> stringStringMap = TokenUtil.parseToken(token);
                Long userId = Long.parseLong(stringStringMap.get("userId"));
                if(ObjectUtil.isNull(vo.getUserId()) || !NumberUtil.equals(vo.getUserId(),userId)){
                    log.error("add order has wrong: "+ ResultEnumCode.ITEM_NOT_EXISTS_ERR.getMessage());
                    throw new OrderException(ResultEnumCode.USER_INVALID);
                }

                DmOrder order = new DmOrder();
                order.setOrderNo(snowFlakeId);
                order.setOrderType(0L);//下单未支付
                order.setInvoiceNo(vo.getInvoiceId());
                order.setInvoiceHead(vo.getInvoiceHead());
                order.setIsNeedInsurance(vo.getIsNeedInsurance());
                order.setItemId(dmItem.getId());
                order.setItemName(dmItem.getItemName());
                //支付类型默认为 1：支付宝,无需设置
                //支付终端默认为 0：WEB端,无需设置
                order.setScheduleId(vo.getSchedulerId());
                order.setUserId(userId);

                //1,2,3
                //1_1,2_1,3_1
                //设置总票数： 购票人数量和购票数量一致
                String[] linkIdsArr = vo.getLinkIds().split(",");
                String[] seatPositionsArr = vo.getSeatPositions().split(",");
                if(!NumberUtil.equals(linkIdsArr.length, seatPositionsArr.length)){
                    log.error("add order has wrong: "+ ResultEnumCode.ORDER_INFO_INVALID.getMessage());
                    throw new OrderException(ResultEnumCode.ORDER_INFO_INVALID);
                }else{
                    //订单的总座位数
                    order.setTotalCount((long) linkIdsArr.length);
                }
                //查询每一个订单座位
                //计算每个座位的价格

                //计算座位及价格的同时新增订单联系人信息
                List<DmOrderLinkUser> orderLinkUsers = new ArrayList<>();
                Long totalAmount = 0L;
                //List<DmSchedulerSeat> seatsParam = new ArrayList<>();
                for (int i = 0;i < seatPositionsArr.length;i++) {

                    //查询联系人信息
                    DmLinkUser dmLinkUser = linkUserFeign.linkUser(Long.parseLong(linkIdsArr[i]));
                    if(ObjectUtil.isNull(dmLinkUser)){
                        //订单新增联系人不存在
                        log.error("add order has wrong: "+ ResultEnumCode.ORDER_LINK_USER_NOT_EXISTS_ERROR.getMessage());
                        throw new OrderException(ResultEnumCode.ORDER_LINK_USER_NOT_EXISTS_ERROR);
                    }

                    //1_1
                    String s = seatPositionsArr[i];
                    //拆分座位
                    long x = Long.parseLong(s.split("_")[0]);
                    long y = Long.parseLong(s.split("_")[1]);
                    DmSchedulerSeat seat = seatFeign.seatDetail(vo.getSchedulerId(), x, y);
                    if(ObjectUtil.isNull(seat)){
                        log.error("add order has wrong: "+ ResultEnumCode.ORDER_INFO_INVALID.getMessage());
                        throw new OrderException(ResultEnumCode.ORDER_INFO_INVALID);
                    }
                    if(seat.getOrderNo()!=null && seat.getUserId()!=null && seat.getStatus()!=1L){
                        //座位已经出售，不可下单购买
                        log.error("add order has wrong: "+ ResultEnumCode.SEAT_HAS_BEEN_SALED_ERR.getMessage());
                        throw new OrderException(ResultEnumCode.SEAT_HAS_BEEN_SALED_ERR);
                    }
                    //查询每一个座位价格
                    Long price = seatPriceFeign.seatPrice(seat.getScheduleId(), seat.getAreaLevel());
                    totalAmount += price;

                    //新增订单联系人数据
                    DmOrderLinkUser orderLinkUser = new DmOrderLinkUser();
                    orderLinkUser.setOrderId(snowFlakeId);
                    orderLinkUser.setX(x);
                    orderLinkUser.setY(y);
                    orderLinkUser.setLinkUserId(Long.parseLong(linkIdsArr[i]));
                    orderLinkUser.setLinkUserName(dmLinkUser.getName());
                    orderLinkUser.setPrice(price);
                    //orderLinkUsers 执行批量新增
                    orderLinkUsers.add(orderLinkUser);


                    //锁定座位
                    //seat.setOrderNo(snowFlakeId);
                    //seat.setUserId(userId);
                    //seat.setStatus(2L);
//                    Map<String, Object> params = new HashMap<>();
//                    //修改条件
//                    params.put("scheduleId",vo.getSchedulerId());
//                    params.put("updatedTime", LocalDateTime.now());
//                    params.put("x",x);
//                    params.put("y",y);
//                    //修改信息
//                    params.put("orderNo",snowFlakeId);
//                    params.put("userId",userId);
//                    params.put("status",2L);//锁定待付款
                    /**
                     *
                     */
                    //seatsParam.add(seat);
                }


                //changeSeatByOrder(seatsParam);//手写sql，mp字段填充失效

                //是否需要购买保险，如果需要则在总金额基础之上+20
                if(vo.getIsNeedInsurance() == 1L){
                    totalAmount+=20;
                }
                order.setTotalAmount(totalAmount);
                try{
                    LocalDateTime now = LocalDateTime.now();
                    //订单编号
                    txMsg.put("orderNo",snowFlakeId);
                    txMsg.put("userId",userId);
                    txMsg.put("atime",now);
                    txMsg.put("linkIds",linkIdsArr);
                    txMsg.put("seatPositions",seatPositionsArr);
                    txMsg.put("scheduleId",vo.getSchedulerId());

                    OrderTxMsg msg = new OrderTxMsg();
                    msg.setId(snowFlakeId);
                    msg.setMsg(JSONUtil.toJsonStr(txMsg));
                    msg.setAtime(now);
                    msg.setBizType("1");
                    msg.setMsgResult("0");
                    msg.setVersion(1);
                    msg.setTryCount(1);
                    txMsgService.save(msg);
                    //订单和联系人在同一数据库，使用本地事务即可处理
                    //该操作出现异常则会影响到排期数据库的数据一致，所以需要分布式事务
                    /**
                     *
                     */
                    orderService.save(order);//订单新增到数据库
                    /**
                     *
                     */
                    orderLinkUserService.saveBatch(orderLinkUsers);//批量新增订单联系人
                    //向rabbitmq发送一条消息，表示生产者已经完成数据修改并进行了消息投递
                    CorrelationData correlationData = new CorrelationData(snowFlakeId);
                    rabbitTemplate.convertAndSend("dm_order_exchange","dm.order.tx",msg,correlationData);
//                    int i = 1/0;
                }catch (RuntimeException e){
                    //此时需要进行排期数据"回滚"
                    //通过异步消息 fanout 通过该交换器 mq会将发送的message同时发送给每一个交换器绑定的队列
                    rabbitTemplate.convertAndSend("dm_order_rollback_exchange","",snowFlakeId);
                    throw e;
                }

                //将生成的订单号发送到mq的普通队列dm_order_queue
                //同时记录订单消息在队列中的存活时长
                rabbitTemplate.convertAndSend(rabbitConfig.getOrder_exchange(),rabbitConfig.getOrder_routing_key(),
                        snowFlakeId,message -> {
                            message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                            message.getMessageProperties().setExpiration("900000");
                            return message;
                        });
                return snowFlakeId;
            }finally {
                lock.unlock();
//                lockHandler.releaseLock(lock);
            }
        }
        return null;
    }

    @Override
    public boolean chageOrderStatus(String orderNo, Long orderType) {
        //update table set orderType=? where orderNo=?
        UpdateWrapper<DmOrder> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("orderType",orderType);
        updateWrapper.eq("orderNo",orderNo);
        return orderService.update(updateWrapper);
    }

    @Override
    public boolean changeSeatByOrder(List<DmSchedulerSeat> params) {
        return seatFeign.changeSeatByOrder(params);
    }
}
